package geom;

/**
 * some essential geometry calculations that are useful for dealing with vectors
 * 
 * @author Robbe
 *
 */
public class Geometry {
	
	// TODO clarify : (homogeneous points (4x1) != homogeneous vectors (4x1) != vectors (3x1) )
	
	public static String homogeneousToString(double[] coordinates) {
		assert(coordinates.length % 4 == 0);
		StringBuilder sb = new StringBuilder();
		for (int i = 0; i < coordinates.length/4; i++) {
			sb.append(coordinates[i*4+0]).append('\t').append(coordinates[i*4+1]).append('\t').append(coordinates[i*4+2]).append('\t').append(coordinates[i*4+3]).append('\n');
		}
		return sb.toString();
	}
	
	public static String vectorToString(double[] coordinates) {
		assert(coordinates.length % 3 == 0);
		StringBuilder sb = new StringBuilder();
		for (int i = 0; i < coordinates.length/3; i++) {
			sb.append(coordinates[i*4+0]).append('\t').append(coordinates[i*4+1]).append('\t').append(coordinates[i*4+2]).append('\n');
		}
		return sb.toString();
	}	
	
	public static double homogeneousLength(double[] vectors, int i) {		
		assert(vectors.length % 4 == 0);
		double x = vectors[i*4 + 0];
		double y = vectors[i*4 + 1];
		double z = vectors[i*4 + 2];
		
		return Math.sqrt(x*x + y*y + z*z);
	}
	
	public static double dotProduct(double[] v1, double v2[]) {
		return v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2];		
	}
	
	 
	
	public static double[] crossProduct(double[] v1, double[] v2) {
		return new double[]{
			    v1[1]*v2[2] - v1[2]*v2[1],
			    v1[2]*v2[0] - v1[0]*v2[2],
			    v1[0]*v2[1] - v1[1]*v2[0]				
		};
	}
	
	public static double norm(double[] v) {
		return Math.sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]);
	}
	
	
	public static void normalize(double[] v) {
		double l = norm(v);
		v[0] /= l;
		v[1] /= l;
		v[2] /= l;
	}
	
	public static double[] normalized(double[] v) {
		double l = norm(v);
		return new double[]{				
				v[0] / l,
				v[1] / l,
				v[2] / l				
		};
	}
	
	public static void multiply(double v[], double s) {
		v[0] *= s;
		v[1] *= s;
		v[2] *= s;
	}
	
	public static double[] product(double v[], double s) {
		return new double[] {
				v[0] * s,
				v[1] * s,
				v[2] * s
		};
	}
	
	public static void add(double[] v, double[] s) {
		v[0] += s[0];
		v[1] += s[1];
		v[2] += s[2];
	}
	
	public static double[] sum(double[] v1, double[] v2) {
		return new double[]{
				v1[0] + v2[0],
				v1[1] + v2[1],
				v1[2] + v2[2]
		};		
	}
	
	public static double[] difference(double[] v1, double[] v2) {
		return new double[]{
				v1[0] - v2[0],
				v1[1] - v2[1],
				v1[2] - v2[2]
		};		
	}
	
    public static double[] computeNormal(double[] v1, double[] v2, double[] v3) {
        double[] a = difference(v3, v1);
        double[] b = difference(v2, v1);

        return normalized(crossProduct(a, b));
    }
    
    public static double[] componentProduct(double[] v1, double[] v2) {
    	return new double[]{
    			v1[0] * v2[0],
    			v1[1] * v2[1],
    			v1[2] * v2[2]
    	};
    }
	
	public static double[] linearCombination(double a, double[] v1, double b, double[] v2) {
		return new double[] {
				a*v1[0] + b*v2[0], 
				a*v1[1] + b*v2[1],
				a*v1[2] + b*v2[2]
		};
	}
	
	public static double[] linearCombination(double a, double[] v1, double b, double[] v2, double c, double[] v3) {
		return new double[] {
				a*v1[0] + b*v2[0] + c*v3[0], 
				a*v1[1] + b*v2[1] + c*v3[1],
				a*v1[2] + b*v2[2] + c*v3[2]
		};
	}	
	
}
